import 'package:flutter/painting.dart';
import 'package:ideology/shared/widgets/code_input/core/text_buffer.dart';
import 'package:ideology/shared/widgets/code_input/highlight/highlight_theme.dart';
import 'package:ideology/shared/widgets/code_input/highlight/regex_lexer.dart';
import 'package:ideology/shared/widgets/code_input/highlight/token.dart';

/// **增量式、逐行的语法高亮器**。
///
/// - 内部基于 [RegexLexer] 进行逐行词法分析，支持关键字、注释、字符串、数字等。
/// - 维护行级缓存，避免整段文本在每次改动后都被完全重算。
/// - 适合在编辑器控件中进行实时高亮。
///
/// ### 工作原理
/// 1. 调用 [rebuildIfNeeded]，传入 [TextBuffer]；
/// 2. 比较当前文本行与上次快照，找到第一个变更行；
/// 3. 从该行开始重新 lex，并将状态向后传播（支持跨行注释/字符串）；
/// 4. 将生成的 token 缓存起来；
/// 5. 渲染时调用 [buildSpansForLine]，将 token 转换为带样式的 [InlineSpan]。
///
/// ### 缓存字段
/// - [_lineInState]：每行进入时的 lexer 状态；
/// - [_lineOutState]：每行分析完成后的状态；
/// - [_lineTokens]：每行对应的 token 列表；
/// - [_lastLines]：上次完整的行文本快照；
/// - [_bufferVersion]：绑定的 [TextBuffer.version]；
/// - [_version]：高亮版本号，每次 token 改变时递增。
class SyntaxHighlighter {
  final RegexLexer _lexer;
  final HighlightTheme theme;

  // 缓存的逐行状态与结果
  final List<LexState> _lineInState = <LexState>[];
  final List<LexState> _lineOutState = <LexState>[];
  final List<List<Token>> _lineTokens = <List<Token>>[];
  List<String> _lastLines = <String>[];
  int _bufferVersion = -1;

  /// 高亮版本号：每次 token 结果变更都会递增。
  int _version = 0;

  SyntaxHighlighter({
    required Set<String> keywords,
    required this.theme,
  }) : _lexer = RegexLexer(keywords: keywords);

  int get version => _version;

  /// 确保缓存与 [buffer] 一致。
  ///
  /// - 对比当前文本行与 [_lastLines]，找到第一个不同的行；
  /// - 从该行开始，调用 [_lexer.tokenizeLine] 重新分析；
  /// - 将状态向后传播，直到文本结尾或状态稳定；
  /// - 若检测到文本与缓存完全一致（包括版本号、行数、行内容），则直接跳过。
  void rebuildIfNeeded(TextBuffer buffer) {
    final lines = buffer.getLines();
    final n = lines.length;

    // 确保缓存数组大小 >= 行数
    void ensureSize(int size) {
      while (_lineInState.length < size) {
        _lineInState.add(LexState.normal);
      }
      while (_lineOutState.length < size) {
        _lineOutState.add(LexState.normal);
      }
      while (_lineTokens.length < size) {
        _lineTokens.add(<Token>[]);
      }
    }
    ensureSize(n);

    // 找到第一个差异行
    int start = 0;
    final m = _lastLines.length;
    final limit = n < m ? n : m;
    bool found = false;
    for (int i = 0; i < limit; i++) {
      if (lines[i] != (_lastLines.isNotEmpty ? _lastLines[i] : null)) {
        start = i;
        found = true;
        break;
      }
    }
    if (!found) {
      start = limit; // 没有行差异，但可能是增加/删除行
    }

    // 如果版本号与行内容完全一致，直接返回
    if (_bufferVersion == buffer.version && n == _lastLines.length) {
      bool allSame = true;
      for (int i = 0; i < n; i++) {
        if (lines[i] != _lastLines[i]) {
          allSame = false;
          break;
        }
      }
      if (allSame) return;
    }

    // 从 start 行开始重新 lex，并传播状态
    LexState prevState = start > 0 ? _lineOutState[start - 1] : LexState.normal;
    for (int i = start; i < n; i++) {
      _lineInState[i] = prevState;
      final res = _lexer.tokenizeLine(lines[i], prevState);
      final tokens = res.tokens;
      final out = res.outState;
      prevState = out;

      final oldTokens = _lineTokens[i];
      final oldOut = _lineOutState[i];
      if (!_tokensEqual(oldTokens, tokens) || oldOut != out) {
        // 如果 token 或状态有变更，则更新缓存
        _lineTokens[i] = tokens;
        _lineOutState[i] = out;
      } else {
        // 如果当前行无变化，并且后续行文本也完全一致，则提前退出
        bool subsequentStable = true;
        for (int j = i + 1; j < n && j < _lastLines.length; j++) {
          if (lines[j] != _lastLines[j]) {
            subsequentStable = false;
            break;
          }
        }
        if (subsequentStable && n == _lastLines.length) {
          break;
        }
      }
    }

    // 更新快照
    _lastLines = List<String>.from(lines);
    _bufferVersion = buffer.version;
    _version++;
  }

  /// 比较两组 token 是否完全一致。
  bool _tokensEqual(List<Token> a, List<Token> b) {
    if (identical(a, b)) return true;
    if (a.length != b.length) return false;
    for (int i = 0; i < a.length; i++) {
      final x = a[i], y = b[i];
      if (x.start != y.start || x.end != y.end || x.type != y.type) return false;
    }
    return true;
  }

  /// 将某一行的 token 构建为 [InlineSpan] 列表，用于渲染。
  ///
  /// - [lineIndex]：行号；
  /// - [line]：原始行字符串；
  /// - 返回：每个 token 对应的 [TextSpan]，样式取自 [HighlightTheme]。
  List<InlineSpan> buildSpansForLine(int lineIndex, String line) {
    if (lineIndex >= _lineTokens.length) {
      return [TextSpan(text: line, style: theme.base)];
    }
    final toks = _lineTokens[lineIndex];
    if (toks.isEmpty) return [TextSpan(text: line, style: theme.base)];

    final spans = <InlineSpan>[];
    for (final t in toks) {
      final sub = (t.start >= 0 && t.end <= line.length && t.start <= t.end)
          ? line.substring(t.start, t.end)
          : '';
      spans.add(TextSpan(text: sub, style: _styleFor(t.type)));
    }
    return spans;
  }

  /// 根据 token 类型选择对应的样式。
  TextStyle _styleFor(TokenType t) {
    switch (t) {
      case TokenType.keyword: return theme.keyword;
      case TokenType.string: return theme.string;
      case TokenType.comment: return theme.comment;
      case TokenType.number: return theme.number;
      case TokenType.identifier: return theme.identifier;
      case TokenType.punctuation: return theme.punctuation;
      case TokenType.operator_: return theme.operator_;
      case TokenType.whitespace: return theme.whitespace;
      case TokenType.other: return theme.base;
    }
  }
}
